﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace ZK.Pack
{
    public class TcpLongPrinter 
    {

        private IPEndPoint remotePoint;

        Socket clientSocketToService;
      
        byte[] result = new byte[1024];

        public event EventHandler EventHandlerReceived;
        public event EventHandler EventHandlerError;

        private string _ip;
        public TcpLongPrinter(string ip,int portName)
        {
            _ip = ip;
          //  string[] ls = Regex.Split(portName, ":", RegexOptions.IgnoreCase);
            try
            {
                this.remotePoint = new IPEndPoint(IPAddress.Parse(ip), portName);
                this.portName = ip+":"+ portName.ToString();
            }
           catch {
                throw new Exception(string.Format("{0}格式不正确", portName));
            }
            
        }
        private bool isOpen = false;
        public bool IsOpen {
            get { return isOpen; }
            set {
                isOpen = value;
            }

        }

        private string portkey;
        public string PortKey
        {
            get { return portkey; }
            set
            {
                portkey = value;
            }
        }


        private string portName;
        public string PortName
        {
            get { return portName; }
            set
            {
                portName = value;
            }
        }



        public void EventErrMes(string err)
        {
            if (EventHandlerError != null)
            {

                EventHandlerError(err, null);
            }
        }


        public virtual void Close()
        {
            if (this.clientSocketToService != null && this.clientSocketToService.Connected)
            {
                this.clientSocketToService.Disconnect(false);
            }
            if (this.clientSocketToService != null)
            {
                Thread.Sleep(200);
                if (this.clientSocketToService != null)
                {
                    this.clientSocketToService.Close();
                }
            }

        }

        private bool IsOnLine(string ip)
        {

            Ping ping = new Ping();

            PingReply pingReply = ping.Send(ip);
            if (pingReply.Status == IPStatus.Success)
            {
                return true;

            }
            else
            {
                return false;
            }
         
        }


        public virtual void Open()
        {
            try
            {

                if (!IsOnLine(_ip))
                {
                    throw new Exception("不在线，ping不通！");
                     
                }
                Connect();
                this.IsOpen = true;
            }
            catch
            {
                if(clientSocketToService!=null)
                clientSocketToService.Close();
                throw new Exception(string.Format("发生异常:{0}连接失败", portName));   
             }

            if (clientSocketToService.Connected == false)
            {
                clientSocketToService.Connect(remotePoint);
            }
            SocketReciveData socketReciveDatum = new SocketReciveData()
            {
                ReciveSocket = this.clientSocketToService
            };
            this.clientSocketToService.BeginReceive(socketReciveDatum.ReciveBuffer, 0, (int)socketReciveDatum.ReciveBuffer.Length, SocketFlags.None, new AsyncCallback(this.DataReceived), socketReciveDatum);
        }

        public  void DataReceived(IAsyncResult ar)
        {

            SocketError socketError;
          
            try
            {
                SocketReciveData asyncState = ar.AsyncState as SocketReciveData;
                int num = asyncState.ReciveSocket.EndReceive(ar, out socketError);
                if (socketError != SocketError.Success)
                {
                    string errorMessage = this.GetErrorMessage(socketError);
                    EventErrMes(errorMessage);

                   
                }
                else if (num != 0)
                {
                    asyncState.memoryStream.Write(asyncState.ReciveBuffer, 0, num);
                    if (asyncState.ReciveSocket.Available <= 0)
                    {
                        byte[] array = asyncState.memoryStream.ToArray();
                        asyncState.memoryStream.Close();
                        if (this.IsOpen)
                        {
                           //字节
                            TcpDataReceived(array);
                        }
                        SocketReciveData socketReciveDatum = new SocketReciveData()
                        {
                            ReciveSocket = asyncState.ReciveSocket
                        };
                        socketReciveDatum.ReciveSocket.BeginReceive(socketReciveDatum.ReciveBuffer, 0, (int)socketReciveDatum.ReciveBuffer.Length, SocketFlags.None, new AsyncCallback(this.DataReceived), socketReciveDatum);
                    }
                    else
                    {
                        asyncState.ReciveSocket.BeginReceive(asyncState.ReciveBuffer, 0, (int)asyncState.ReciveBuffer.Length, SocketFlags.None, new AsyncCallback(this.DataReceived), asyncState);
                    }
                }
            
            }
            catch (Exception ex)
            {
                  
                if(this.IsOpen)
                EventErrMes(ex.Message);
            }
             
        }

        public virtual void TcpDataReceived( object obj)
        {

            this.EventReceived(obj);
        }

        private void Connect()
        {
            if (clientSocketToService == null || clientSocketToService.Connected == false)
            { 
                clientSocketToService = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                clientSocketToService.Connect(remotePoint);
            }
        }

        public virtual void WriteData(string data)
        {
            try
            {
                Connect();
                byte[] senddata = Encoding.UTF8.GetBytes(data);
               
                clientSocketToService.Send(senddata);
            }
            catch
            {
                clientSocketToService.Close();
            }
        }

        public virtual void WriteData(byte[] data)
        {
            try
            {
                Connect();
                clientSocketToService.Send(data);
            }
            catch
            {
                clientSocketToService.Close();
            }
        }

        public void EventReceived(object obj)
        {
            if (EventHandlerReceived != null)
            {
                EventHandlerReceived(obj, null);
            }
        }

        protected string GetErrorMessage(SocketError socketError)
        {
            string msg = null;
            if (socketError <= SocketError.IOPending)
            {
                if (socketError <= SocketError.Success)
                {
                    if (socketError == SocketError.SocketError)
                    {
                        msg = "发生了未指定的 Socket 错误。";
                    }
                    else if (socketError != SocketError.Success)
                    {
                    }
                }
                else if (socketError == SocketError.OperationAborted)
                {
                    msg = "由于 Socket 已关闭，重叠的操作被中止。 ";
                }
                else if (socketError == SocketError.IOPending)
                {
                    msg = "应用程序已启动一个无法立即完成的重叠操作。  ";
                }
            }
            else if (socketError <= SocketError.NotInitialized)
            {
                switch (socketError)
                {
                    case SocketError.Interrupted:
                        {
                            msg = "已取消阻止 Socket 调用的操作。 ";
                            break;
                        }
                    //case 10005:
                    //case 10006:
                    //case 10007:
                    //case 10008:
                    //case 10009:
                    //case 10010:
                    //case 10011:
                    //case 10012:
                    case SocketError.Interrupted | SocketError.AccessDenied | SocketError.Fault:
                    //case 10016:
                    //case 10017:
                    //case 10018:
                    //case 10019:
                    //case 10020:
                    //case 10021:
                    //case 10023:
                    //case 10025:
                    //case 10026:
                    //case 10027:
                    //case 10028:
                    //case 10029:
                    //case SocketError.InvalidArgument | SocketError.TooManyOpenSockets:
                    case SocketError.InvalidArgument | SocketError.TooManyOpenSockets:
                    //case 10032:
                    //case 10033:
                    //case 10034:
                    case SocketError.AddressAlreadyInUse | SocketError.AddressNotAvailable | SocketError.NetworkDown | SocketError.NetworkUnreachable | SocketError.IsConnected | SocketError.NotConnected | SocketError.Shutdown:
                    case SocketError.AddressAlreadyInUse | SocketError.NetworkDown | SocketError.NetworkReset | SocketError.ConnectionReset | SocketError.IsConnected | SocketError.Shutdown | SocketError.TimedOut:
                    case SocketError.AddressAlreadyInUse | SocketError.AddressNotAvailable | SocketError.NetworkDown | SocketError.NetworkUnreachable | SocketError.NetworkReset | SocketError.ConnectionAborted | SocketError.ConnectionReset | SocketError.NoBufferSpaceAvailable | SocketError.IsConnected | SocketError.NotConnected | SocketError.Shutdown | SocketError.TimedOut | SocketError.ConnectionRefused:
                    case SocketError.AddressAlreadyInUse | SocketError.NetworkDown | SocketError.HostDown:
                        {
                            break;
                        }
                    case SocketError.AccessDenied:
                        {
                            msg = "已试图通过被其访问权限禁止的方式访问 Socket。 ";
                            break;
                        }
                    case SocketError.Fault:
                        {
                            msg = " 基础套接字提供程序检测到无效的指针地址。 ";
                            break;
                        }
                    case SocketError.InvalidArgument:
                        {
                            msg = "给 Socket 成员提供了一个无效参数。 ";
                            break;
                        }
                    case SocketError.TooManyOpenSockets:
                        {
                            msg = "基础套接字提供程序中打开的套接字太多。";
                            break;
                        }
                    case SocketError.WouldBlock:
                        {
                            msg = "对非阻止性套接字的操作不能立即完成。";
                            break;
                        }
                    case SocketError.InProgress:
                        {
                            msg = "阻止操作正在进行中。";
                            break;
                        }
                    case SocketError.AlreadyInProgress:
                        {
                            msg = "非阻止性 Socket 已有一个操作正在进行中。 ";
                            break;
                        }
                    case SocketError.NotSocket:
                        {
                            msg = "对非套接字尝试 Socket 操作。 ";
                            break;
                        }
                    case SocketError.DestinationAddressRequired:
                        {
                            msg = "在对 Socket 的操作中省略了必需的地址。 ";
                            break;
                        }
                    case SocketError.MessageSize:
                        {
                            msg = "数据报太长。 ";
                            break;
                        }
                    case SocketError.ProtocolType:
                        {
                            msg = "此 Socket 的协议类型不正确。 ";
                            break;
                        }
                    case SocketError.ProtocolOption:
                        {
                            msg = "对 Socket 使用了未知、无效或不受支持的选项或级别。 ";
                            break;
                        }
                    case SocketError.ProtocolNotSupported:
                        {
                            msg = "未实现或未配置协议。 ";
                            break;
                        }
                    case SocketError.SocketNotSupported:
                        {
                            msg = "在此地址族中不存在对指定的套接字类型的支持。 ";
                            break;
                        }
                    case SocketError.OperationNotSupported:
                        {
                            msg = "协议族不支持地址族。 ";
                            break;
                        }
                    case SocketError.ProtocolFamilyNotSupported:
                        {
                            msg = "未实现或未配置协议族。 ";
                            break;
                        }
                    case SocketError.AddressFamilyNotSupported:
                        {
                            msg = "地址与请求的协议不兼容。 ";
                            break;
                        }
                    case SocketError.AddressAlreadyInUse:
                        {
                            msg = "通常，只允许使用地址一次。 ";
                            break;
                        }
                    case SocketError.AddressNotAvailable:
                        {
                            msg = "选定的地址在此上下文中有效。";
                            break;
                        }
                    case SocketError.NetworkDown:
                        {
                            msg = "网络不可用。";
                            break;
                        }
                    case SocketError.NetworkUnreachable:
                        {
                            msg = "不存在到远程主机的路由。 ";
                            break;
                        }
                    case SocketError.NetworkReset:
                        {
                            msg = "应用程序试图在已超时的连接上设置 KeepAlive。 ";
                            break;
                        }
                    case SocketError.ConnectionAborted:
                        {
                            msg = "此连接由 .NET Framework 或基础套接字提供程序中止。 ";
                            break;
                        }
                    case SocketError.ConnectionReset:
                        {
                            msg = "此连接由远程对等计算机重置。 ";
                            break;
                        }
                    case SocketError.NoBufferSpaceAvailable:
                        {
                            msg = "没有可用于 Socket 操作的可用缓冲区空间。 ";
                            break;
                        }
                    case SocketError.IsConnected:
                        {
                            msg = "Socket 已连接。 ";
                            break;
                        }
                    case SocketError.NotConnected:
                        {
                            msg = "应用程序试图发送或接收数据，但是 Socket 未连接。 ";
                            break;
                        }
                    case SocketError.Shutdown:
                        {
                            msg = "发送或接收数据的请求未得到允许，因为 Socket 已被关闭。 ";
                            break;
                        }
                    case SocketError.TimedOut:
                        {
                            msg = "连接尝试超时，或者连接的主机没有响应。";
                            break;
                        }
                    case SocketError.ConnectionRefused:
                        {
                            msg = "远程主机正在主动拒绝连接。";
                            break;
                        }
                    case SocketError.HostDown:
                        {
                            msg = "由于远程主机被关闭，操作失败。 ";
                            break;
                        }
                    case SocketError.HostUnreachable:
                        {
                            msg = "没有到指定主机的网络路由。 ";
                            break;
                        }
                    case SocketError.ProcessLimit:
                        {
                            msg = "正在使用基础套接字提供程序的进程过多。 ";
                            break;
                        }
                    default:
                        {
                            switch (socketError)
                            {
                                case SocketError.SystemNotReady:
                                    {
                                        msg = "网络子系统不可用。 ";
                                        break;
                                    }
                                case SocketError.VersionNotSupported:
                                    {
                                        msg = "基础套接字提供程序的版本超出范围。 ";
                                        break;
                                    }
                                case SocketError.NotInitialized:
                                    {
                                        msg = "尚未初始化基础套接字提供程序。 ";
                                        break;
                                    }
                            }
                            break;
                        }
                }
            }
            else if (socketError == SocketError.Disconnecting)
            {
                msg = "正常关机正在进行中。 ";
            }
            else if (socketError == SocketError.TypeNotFound)
            {
                msg = "未找到指定的类。 ";
            }
            else
            {
                switch (socketError)
                {
                    case SocketError.HostNotFound:
                        {
                            msg = "无法识别这种主机。该名称不是正式的主机名或别名。 ";
                            break;
                        }
                    case SocketError.TryAgain:
                        {
                            msg = "无法解析主机名。请稍后重试。 ";
                            break;
                        }
                    case SocketError.NoRecovery:
                        {
                            msg = "错误不可恢复或找不到请求的数据库。 ";
                            break;
                        }
                    case SocketError.NoData:
                        {
                            msg = "在名称服务器上找不到请求的名称或 IP 地址。";
                            break;
                        }
                }
            }
            return msg;
        }
    }

    public class SocketReciveData
    {
        private const int BufferSize = 2048;
        public byte[] ReciveBuffer = new byte[2048];
        public Socket ReciveSocket;
        public MemoryStream memoryStream = new MemoryStream();

    }

  

}
